{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Linear Regression"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We will follow the example given by [scikit-learn](https://scikit-learn.org/stable/auto_examples/linear_model/plot_ols.html), and use the [diabetes](https://www4.stat.ncsu.edu/~boos/var.select/diabetes.html) dataset to train and test a linear regressor. We begin by loading the dataset (using only two features for this example) and splitting it into training and testing samples (an 80/20 split)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Train examples: 353, Test examples: 89\n"
     ]
    }
   ],
   "source": [
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn import datasets\n",
    "\n",
    "dataset = datasets.load_diabetes()\n",
    "X_train, X_test, y_train, y_test = train_test_split(dataset.data[:, :2], dataset.target, test_size=0.2)\n",
    "print(\"Train examples: %d, Test examples: %d\" % (X_train.shape[0], X_test.shape[0]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Non-private baseline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We now use scikit-learn's native LinearRegression function to establish a non-private baseline for our experiments. We will use the [r-squared score](https://en.wikipedia.org/wiki/Coefficient_of_determination) to evaluate the goodness-of-fit of the model, which is built into LinearRegression. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Non-private baseline R2 score: 0.06\n"
     ]
    }
   ],
   "source": [
    "from sklearn.linear_model import LinearRegression as sk_LinearRegression\n",
    "\n",
    "regr = sk_LinearRegression()\n",
    "regr.fit(X_train, y_train)\n",
    "baseline = regr.score(X_test, y_test)\n",
    "print(\"Non-private baseline R2 score: %.2f\" % baseline)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Differentially private Linear Regression"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's now train a differentially private linear regressor, where the trained model is differentially private with respect to the training data. We will pass additional hyperparameters to the regressor later to suppress the `PrivacyLeakWarning`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "R2 score for epsilon=1.00: -0.02\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      ".../site-packages/diffprivlib/models/linear_regression.py:266: PrivacyLeakWarning: Bounds parameters haven't been specified, so falling back to determining bounds from the data.\n",
      "This will result in additional privacy leakage. To ensure differential privacy with no additional privacy loss, specify `bounds_X` and `bounds_y`.\n",
      "  warnings.warn(\n"
     ]
    }
   ],
   "source": [
    "from diffprivlib.models import LinearRegression\n",
    "\n",
    "regr = LinearRegression()\n",
    "regr.fit(X_train, y_train)\n",
    "\n",
    "print(\"R2 score for epsilon=%.2f: %.2f\" % (regr.epsilon, regr.score(X_test, y_test)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Plotting r-squared versus epsilon"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We want to evaluate the tradeoff between goodness-of-fit and privacy budget (epsilon), and plot the result using `matplotlib`. For this example, we evaluate the score for epsilon between 1e-2 and 1e2. To ensure no privacy leakage from the hyperparameters of the model, `data_norm`, `range_X` and `range_y` should all be set independently of the data, i.e. using domain knowledge. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "\n",
    "epsilons = np.logspace(-1, 2, 100)\n",
    "accuracy = []\n",
    "\n",
    "for epsilon in epsilons:\n",
    "    regr = LinearRegression(epsilon=epsilon, bounds_X=(-0.138, 0.2), bounds_y=(25, 346))\n",
    "    regr.fit(X_train, y_train)\n",
    "    \n",
    "    accuracy.append(regr.score(X_test, y_test))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And then plot the result in a semi-log plot."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.legend.Legend at 0x7f481f531dc0>"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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fj92796N9evXo7y8POm6/fr1Q5cuXfDll19iz549GDlyJLp06ZKwXu/evTF+/HgAwIUXXoh58+bht7/9LQDgvPPOS1jf7XZjypQpWLRoEaZPn463334b9913n+H5ff7551i/fn1kn62trTjmmGNSHruK1+uNaDCjR4/G+++/DwBYsmRJjB+jtrYW9fX1qKmpwSWXXIJNmzaBiODz+SLrnHLKKejcuXPS/Ri5jnV1dTjzzDNRWFiIwsJCnH766TFjqOfv66+/xtq1a3HKKacACJnyDj/8cABAeXk5Zs2ahbPOOgtnnXUWAGD8+PG47rrrMGvWLJx99tno1atXzLhLly7Fr371KwDA4MGD0bdvX3zzzTcAgJNOOgllZWUAgKFDh2Lr1q3o3bu34fMr5D9O+ygWAngMwDOZGOyO04dlYpi02bx5M1wuF7p3744NGzYY2oaZccstt+DKK6+MWV5VVYWSkhJD6xUUFEQ+u1yulA7yLVu24IEHHsCKFStwyCGH4NJLL00Z5njFFVdg4cKF+P7773HZZZclXSc+Cib6c/SxRHP++efjscceQ+fOnVFZWYnS0lLD82NmnHLKKXjhhRd0566Fx+OJzNHlcsHv9wMAgsEgPv/8cxQWFsasf/XVV2PSpEl44403UFVVhRNOOCHl8cV/p3Udo017emMwM4YNG4Zly5YlrPP222/jk08+waJFi3DPPffgv//9L26++WZMnToV77zzDsaPH4/33nsv4bi0iP+/Us+PcPDgqI+CmT8B8IOTc8g0+/btw9y5c3H11VebChucPHkynnrqqYhtfefOndi7d6/l9aIpLS1FXV1dwvLa2lqUlJSgrKwMe/bswT//+c+U8/zZz36Gd999FytWrMDkyZOTrrNt27bIA+z555/HhAkTUo47ceJErFq1Ck888UTErq43v+hjGjduHD777DN8++23AICGhobI23A6nHrqqXj00Ucjn9UghJqaGvTs2RNAyIZvBa3rOH78eCxatAjNzc2or6/HP/7xj6TbDxo0CPv27YucZ5/Ph3Xr1iEYDGL79u2YNGkS7r33XtTU1KC+vh7fffcdjj76aNx0000YM2YMNm7cGDPecccdh+eeew4A8M0332Dbtm0YNGiQpWMT2h9OaxQpIaI5AOYAQJ8+fRyeTXKamppQUVEBn88Ht9uNiy66CNddd52pMU49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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "\n",
    "plt.semilogx(epsilons, accuracy, label=\"Differentially private linear regression\", zorder=10)\n",
    "plt.semilogx(epsilons, baseline * np.ones_like(epsilons), dashes=[2,2], label=\"Non-private baseline\", zorder=5)\n",
    "plt.xlabel(\"epsilon\")\n",
    "plt.ylabel(\"r-squared score\")\n",
    "plt.ylim(-5, 1.5)\n",
    "plt.xlim(epsilons[0], epsilons[-1])\n",
    "plt.legend(loc=2)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
